package main

import (
	"context"
	"gitee.com/qzcsu/go-web-study/client"
	"gitee.com/qzcsu/go-web-study/controller/consul"
	gin2 "gitee.com/qzcsu/go-web-study/controller/gin"
	"gitee.com/qzcsu/go-web-study/controller/gorm"
	"gitee.com/qzcsu/go-web-study/controller/grpc"
	"gitee.com/qzcsu/go-web-study/controller/kafka"
	"github.com/gin-gonic/gin"

	"io"
	"log"
	"net/http"
	"os"
	"os/signal"
	"time"
)

func main() {
	client.Init()
	// kafka 启动消费者协程，监听消费消息 KConsumer 执行单个topic 以及offset消费 KConsumerGroup指定消费者组，消费，一个消费者组可以指定不同的topic
	go kafka.KConsumer()
	go kafka.KConsumerGroup()
	r := gin.Default()
	// 全局中间件
	// Logger 中间件将日志写入 gin.DefaultWriter，即使你将 GIN_MODE 设置为 release。
	// By default gin.DefaultWriter = os.Stdout
	//r.Use(gin.Logger())
	// Recovery 中间件会 recover 任何 panic。如果有 panic 的话，会写入 500。
	r.Use(gin.Recovery())
	// 使用自定义的中间件
	r.Use(recordTime())

	//// =====使用skywalking链路追踪，但是未成功 start
	//report, err := reporter.NewGRPCReporter("127.0.0.1:11800")
	//if err != nil {
	//	log.Fatalf("crate grpc reporter error: %v \n", err)
	//}
	//
	//log.Println("go2sky.NewTracer")
	//tracer, err := go2sky.NewTracer("go-web-st", go2sky.WithReporter(report))
	//if err != nil {
	//	log.Fatalf("crate tracer error: %v \n", err)
	//}
	//r.Use(v3.Middleware(r, tracer))
	//// =====使用skywalking链路追踪，但是未成功 end
	// 记录日志
	f, err := os.Create("web.log")
	if err != nil {
		return
	}
	// 自定义日志格式
	//gin.DebugPrintRouteFunc = func(httpMethod, absolutePath, handlerName string, nuHandlers int) {
	//	log.Printf("endpoint %v %v %v %v\n", httpMethod, absolutePath, handlerName, nuHandlers)
	//}

	// 同时记录到文件和标准输出
	gin.DefaultWriter = io.MultiWriter(f, os.Stdout)

	// 每个路由也可以添加相应的中间件，类似钩子函数一样
	r.GET("/ping", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{
			"message": "success",
		})
	})

	// gorm 学习 增删查改
	r.GET("/create/", gorm.AddUser)
	r.GET("/select/", gorm.SelectUser)
	r.GET("/delete/", gorm.DelUser)
	r.GET("/update/", gorm.UpdateUser)

	// gin学习
	r.GET("/get_product/", gin2.GProduct)         // get url传参绑定到结构体中
	r.POST("/post_form_product/", gin2.PFProduct) // post form 请求头传参获取
	r.GET("/json/", gin2.GetJson)                 // json 有些特殊字符转移 可能要用 pure_json
	r.GET("/pure_json/", gin2.GetPureJson)
	r.POST("/post_urlencoded/", gin2.PAXProduct) // post application/x-www-form-urlencoded 请求头 传参获取
	r.GET("/get_xml/", gin2.XML)                 // 返回体为xml格式
	r.GET("/get_yaml/", gin2.YAML)               // 返回体为yaml格式
	r.GET("/get_proto/", gin2.ProtoBuf)          // 返回体序列化Wie protoBuffer
	r.POST("/post_json/", gin2.PostJson)         // post 请求头为 application/json 最常用的传参方式，绑定参数到结构体

	// 支持BasicAuth功能 gin.Accounts 是 map[string]string 的一种快捷方式 里面放置，(key,value) (用户名,密码) 这里装合法的用户名和密码，否则会一直401，前端网页一直弹框输入账号密码
	auth := r.Group("/admin/", gin.BasicAuth(gin.Accounts{
		"sun": "sun_sun",
		"tom": "tom_tom",
	}))
	auth.GET("/sec/", gin2.BasicAuth)

	r.GET("/goroutine/", gin2.Goroutine) //使用 goroutine
	r.GET("/cookie/", gin2.OpCookie)     // 从 request header中cookie 中获取值，设置 response header 中的 cookie
	r.GET("/redirect/", gin2.Redirect)   // 三种请求重定向的方式
	// gin学习结束

	// kafka 学习
	kafkaGroup := r.Group("/kafka/")
	kafkaGroup.POST("/syn_send/", kafka.KafkaSyncSend)
	kafkaGroup.POST("/syn_sends/", kafka.KafkaSyncMultiSend)
	kafkaGroup.POST("/asyn_send/", kafka.KafkaAsyncSend)

	// grpc 学习
	grpcGroup := r.Group("/grpc/")
	grpcGroup.POST("/say_hello/", grpc.NotifyHello)

	// consul 学习
	consulGroup := r.Group("/consul/")
	consulGroup.GET("/health/", consul.HealthCheck)
	consulGroup.GET("/add_black_id/", consul.AddBlackSvrID)

	// r.Run(":80")
	// 自定义httpServer的配置
	s := &http.Server{
		Addr:           ":80",
		Handler:        r,
		ReadTimeout:    10 * time.Second,
		WriteTimeout:   10 * time.Second,
		MaxHeaderBytes: 1 << 20,
	}
	err = s.ListenAndServe()
	// 非终端错误 打印错误关闭服务
	if err != nil && err != http.ErrServerClosed {
		log.Fatalf("listen server err:%v", err)
	}
	// 优雅关闭 等待系统中断信号
	quit := make(chan os.Signal)
	signal.Notify(quit, os.Interrupt)
	<-quit
	log.Println("shutdown server ...")
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	if serr := s.Shutdown(ctx); serr != nil {
		log.Fatal("Server Shutdown:", serr)
	}
	log.Println("Server exiting")
}

func recordTime() gin.HandlerFunc {
	return func(c *gin.Context) {
		t := time.Now()
		//设置上下文变量值，可以在真正的请求中获取到
		c.Set("contentParam", "1")

		//请求前

		c.Next() //调用真正的请求

		//请求后
		costTime := time.Since(t)
		log.Println("costTime: ", costTime)
		log.Println("请求响应的状态码: ", c.Writer.Status())
	}
}
